#!/usr/bin/env python3.10
# -*- encoding: utf-8 -*-
"""
@File    :   schema.py
@Time    :   2024/01/30 16:43:59
@Author  :   windstarry 
@Version :   1.0
"""
# here put the import lib

from typing import Any, Optional

from pydantic import BaseModel
from pydantic.networks import AnyUrl
from typing_extensions import Annotated
from django.db import transaction
from django.urls import reverse
from ninja_schema import ModelSchema, Schema, model_validator
from ninja_extra import service_resolver
from ninja_extra.controllers import RouteContext
from ninja_extra.exceptions import APIException


from .models import Book, Store, StoreBook, StoreBookSubscription
from core.schemas import CoreModelSchema
from system.schema import UserRetrieveSchema


class OKSchema(BaseModel):
    details: dict


class IdSchema(BaseModel):
    id: Any


class BookSchema(CoreModelSchema):
    created_by: Optional[UserRetrieveSchema]

    class Config:
        model = Book
        include = ("id", "name", "author", "description")


class CreateBookSchema(CoreModelSchema):
    class Config:
        model = Book
        optional = ["created_by"]
        include = ("name", "author", "description")


class StoreRetrieveSchema(ModelSchema):
    owner: UserRetrieveSchema

    class Config:
        model = Store
        include = ["id", "name", "bio"]


class StoreMessage(Schema):
    message: str


class StoreCreateSchema(CoreModelSchema):
    class Config:
        model = Store
        include = [
            "name",
            "bio",
        ]

    @model_validator("name")
    def unique_name(cls, value_data):
        context: RouteContext = service_resolver(RouteContext)
        if context.kwargs.get("store_id"):
            if not Store.objects.filter(
                name__contains=value_data, id=context.kwargs.get("store_id")
            ).exists():
                return value_data
        elif not Store.objects.filter(name__contains=value_data).exists():
            return value_data
        raise APIException("仓库名已存在")

    @transaction.atomic
    def create_store(self, **kwargs: Any):
        _data = self.dict(exclude_none=True)
        _data.update(kwargs)
        return Store.objects.create(**_data)


class StoreUpdateSchema(CoreModelSchema):
    class Config:
        model = Store
        include = [
            "name",
            "bio",
        ]
        optional = "__all__"

    @model_validator("name")
    def unique_name(cls, value_data):
        context: RouteContext = service_resolver(RouteContext)
        if context.kwargs.get("store_id"):
            if not Store.objects.filter(
                name__contains=value_data, id=context.kwargs.get("store_id")
            ).exists():
                return value_data
        elif not Store.objects.filter(name__contains=value_data).exists():
            return value_data
        raise APIException("仓库名已存在")

    @transaction.atomic
    def create_store(self, **kwargs: Any):
        _data = self.dict(exclude_none=True)
        _data.update(kwargs)
        return Store.objects.create(**_data)


class StoreBookSchema(ModelSchema):
    borrowed_by: Optional[UserRetrieveSchema]
    store: Annotated[str, AnyUrl]
    book: BookSchema

    class Config:
        model = StoreBook
        # 不包含字段
        model_exclude = ["description","creator","modifier","update_datetime","create_datetime","sort",]

    @model_validator("store", mode="before")
    def store_validate(cls, value_data):
        context: RouteContext = service_resolver(RouteContext)
        value = reverse("store:store-detail", kwargs=dict(store_id=value_data.id))
        return context.request.build_absolute_uri(value)


class BorrowOrReturnStoreBookSchema(ModelSchema):
    borrowed_by: Optional[UserRetrieveSchema]
    store: Optional[Annotated[str, AnyUrl]]
    book: Optional[BookSchema]

    class Config:
        model = StoreBook
        include = ["borrowed_by", "store", "book"]

    @model_validator("store", mode="before")
    def store_validate(cls, value_data):
        context: RouteContext = service_resolver(RouteContext)
        value = reverse("store:store-detail", kwargs=dict(store_id=value_data.id))
        return context.request.build_absolute_uri(value)


class StoreBookSubscriptionSerializer(ModelSchema):
    store_book: StoreBookSchema
    subscriber: UserRetrieveSchema

    class Config:
        model = StoreBookSubscription
        include = ["store_book", "subscriber", "id"]
